/**
 * @Author: douxuefeng
 * @Date: 2020/11/19 上午9:43
 * @File: jwt
 * @Desc:
 */
package middleware

import (
	"errors"
	comm "gitee.com/douxuefeng/go-common"
	"gitee.com/douxuefeng/go-iris/config"
	"gitee.com/douxuefeng/go-iris/repository"
	"github.com/dgrijalva/jwt-go"
	jwtmiddleware "github.com/iris-contrib/middleware/jwt"
	"github.com/kataras/iris/v12"
	"strings"
	"time"
)

var JwtAuthMiddleware = jwtmiddleware.New(jwtmiddleware.Config{
	ValidationKeyGetter: validationKeyGetterFuc,
	SigningMethod:       jwt.SigningMethodHS256,
	Expiration:          true,
	Extractor:           extractor,
	ErrorHandler: func(c iris.Context, err error) {
		//log.Println(err)
		json := map[string]interface{}{
			"code": 401,
			"msg": err.Error(),
		}
		c.JSON(json)
	},
}).Serve

var validationKeyGetterFuc = func(token *jwt.Token) (interface{}, error) {
	return []byte(config.GetConfig().JwtSecret), nil
}

var extractor = func(ctx iris.Context) (string, error) {
	authHeader := ctx.GetHeader("Authorization")
	if authHeader == "" {
		return "",  nil // No error, just no token
	}
	// TODO: Make this a bit more robust, parsing-wise
	authHeaderParts := strings.Split(authHeader, " ")
	if len(authHeaderParts) != 2 || authHeaderParts[0] != "Bearer" {
		return "",  errors.New("Authorization header format must be Bearer {token}")
	}
	token, err := jwt.Parse(authHeaderParts[1], func(token *jwt.Token) (interface{}, error) {
		return []byte(config.GetConfig().JwtSecret), nil
	})
	if err != nil {
		return "", errors.New("token失效，请重新登录")
	}
	// 单设备登录
	claims,ok := token.Claims.(jwt.MapClaims)
	if !ok  {
		return "", errors.New("token失效，请重新登录")
	}

	aud := claims["aud"].(float64)
	ok = repository.OauthTokenRepository.CheckToken(claims["jti"].(string), claims["iss"].(string), int64(aud))
	if !ok {
		return "", errors.New("token失效，请重新登录")
	}
	return authHeaderParts[1], nil
}

//注册jwt中间件
func ValidToken() *jwtmiddleware.Middleware {
	jwtHandler := jwtmiddleware.New(jwtmiddleware.Config{
		//这个方法将验证jwt的token
		ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
			//自己加密的秘钥或者说盐值
			return []byte(config.GetConfig().JwtSecret), nil
		},
		//加密的方式
		SigningMethod: jwt.SigningMethodHS256,
		//验证未通过错误处理方式
		ErrorHandler: func(ctx iris.Context, e error) {
			ctx.Next()
		},
	})
	return jwtHandler
}

//生成token
func GetToken(id int64, source string ) (access_token string) {
	kid := comm.Uuid()
	now := time.Now()
	secret := config.GetConfig().JwtSecret
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"aud": id,                                                        //openid
		"iss": source,                                                  //签发者
		"iat": now.Unix(),                                         //签发时间
		"jti": kid,                                                      //jwt的唯一身份标识，主要用来作为一次性token,从而回避重放攻击。
		"exp": now.Add(12 * time.Hour).Unix(), //过期时间
	})
	//// 存储一次性token
	repository.OauthTokenRepository.StoreToken(kid, source, id)
	access_token, _ = token.SignedString([]byte(secret))
	return
}
func GetOauth(ctx iris.Context) (aud int64, source string){
	authHeader := ctx.GetHeader("Authorization")
	if authHeader == "" {
		return 0, ""
	}
	authHeaderParts := strings.Split(authHeader, " ")
	token, _ := jwt.Parse(authHeaderParts[1], func(token *jwt.Token) (interface{}, error) {
		return []byte(config.GetConfig().JwtSecret), nil
	})
	claims, ok := token.Claims.(jwt.MapClaims)
	if  !ok {
		return 0,""
	}
	a := claims["aud"].(float64)
	aud = int64(a)
	source = claims["iss"].(string)
	exp := claims["exp"].(float64)
	if int64(exp) < time.Now().Unix() {
		return 0,""
	}
	return
}